#ifndef _HPCR_MAP_H_
#define _HPCR_MAP_H_

#include <stdlib.h>
#include "hpcr_types.h"

#define MAP_KEY_LENGTH 64
#define MAP_PAYLOAD 0.75
#define MAP_DEFAULT_INITIAL_CAPACITY (1 << 4)
#define MAP_ARRAY_INITIAL_CAPACITY 20
/*
 * Map Item
 */

enum map_value_type
{
    MAP_VALUE_TYPE_INVALI,
    MAP_VALUE_TYPE_NUL,
    MAP_VALUE_TYPE_LONG,
    MAP_VALUE_TYPE_DOUBLE,
    MAP_VALUE_TYPE_STRING,
    MAP_VALUE_TYPE_ARRAY,
    MAP_VALUE_TYPE_MAP
};
typedef enum map_value_type MapValueType;

// Initial cap in map parse(src/parse/map/map.y rule: _JOSN_ARRAY) is 20. The growth curve is in line with exponential growth with a base of 2.
struct map_array
{
    MapValueType type;
    int cap;
    int len;
    void *array;
};
typedef struct map_array MapArray;

struct map_value
{
    MapValueType type;
    void *value;
};
typedef struct map_value MapValue;

struct map_item
{
    char key[MAP_KEY_LENGTH];
    uint hash;
    MapValue *value;
};
typedef struct map_item MapItem;

struct map_binary_tree
{
    void *left;
    void *right;
};

/*
 *  Map Index
 */

typedef struct map_binary_tree BinaryTree;

struct map_link_list
{
    void *next;
};
typedef struct map_link_list LinkList;

union map_index_meth
{
    LinkList linkList;
    BinaryTree binaryTree;
};
typedef union map_index_meth MapIndexMeth;

struct map_index_item
{
    MapIndexMeth index;
    MapItem *item;
};
typedef struct map_index_item MapIndexItem;

enum map_entry_data_struct_type
{
    MAP_DATA_STRUCT_LINKLIST,
    MAP_DATA_STRUCT_BINARYTREE
};
typedef enum map_entry_data_struct_type MapEntryDataStructType;

struct map_entry
{
    int len;
    MapEntryDataStructType type;
    MapIndexItem *indexItem;
};
typedef struct map_entry MapEntry;

struct _map
{
    int cap; // the number of entries
    int len; // the number of mapItem member
    MapEntry *entrys;
};
typedef struct _map Map;

void MapFree(Map *map);
void MapItemFree(MapItem *mapItem);
Map *MapInit();
MapValue *MapValueInit(MapValueType mapValueType);
MapItem *MapItemInit(char *key, MapValue *value);
MapItem *MapStringItemInit(char *key, char *data);
MapItem *MapNumberInit(char *key, hpcr_int64_t data);
MapItem *MapDoubleInit(char *key, double data);
MapArray *MapArrayInit();
bool MapPut(Map *map, MapItem *mapItem);
bool MapRemove(Map *map, char *key);
MapItem *MapItemInit(char *key, MapValue *value);
static void MapArrayStringify(MapArray *mapArray, char *buffer);
static void MapEntryStringify(MapEntry *mapEntry, char *buffer);
char *MapString(Map *map, char *buffer);
MapItem *MapGet(Map *map, char *key);

#endif